我們在開發上的各個階段,可能都需要對index做不同的調整
例如在測試過程,想要臨時在已經創建好的index做欄位的變更等等
今天我們就是著重在介紹遇到以下情形以及可能的開發需求時,對應處理的API
新增現有index的欄位:
有時候你沒辦法保證索引的欄位數量不會再改動,並且因為ES本身預備很多彈性,我們在建立索引時的欄位不一定是最終版本,那我們要如何去為現有的索引增加欄位呢?
// 現有的test索引只有name一個欄位
PUT /test
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      }
    }
  }
}
PUT /test/_doc/1
{
  "name": "Eason"
}
PUT /test/_mapping
{
  "properties": {
    "new_field": {
      "type": "text"
    } 
  }
}
GET /test/_mapping

這時候可能會有疑問,這樣我們一開始輸入的文檔會有這個新欄位的預設值嗎?
{
  "_index": "test",
  "_id": "1",
  "_version": 1,
  "_seq_no": 0,
  "_primary_term": 1,
  "found": true,
  "_source": {
    "name": "Eason"
  }
}
我們可以看到_source中沒有新的值,並且因為此時因為新建立欄位是null,無法建立反向索引並且做搜尋等操作
因此我們可以為index field添加默認值,方法有使用script語法跟使用pipeline
我們在後面的章節會再介紹pipeline,所以這邊用script示範
在ES中使用script時通常是要自定義一些項目時會使用到,但是性能可能會因此下降,因此如果非必要盡量不要使用
script的基本語法
"script": {
    "lang":   "...",
    "source" | "id": "...",
    "params": { ... }
}
那我們就讓new_field欄上補上默認值
POST test/_update_by_query
POST /test/_update_by_query
{
  "script": {
    "source": "if (ctx._source.new_field == null) {ctx._source.new_field = 'update!'}",
    "lang": "painless"
  }
}

Reindex API:
那如果我們今天創建了index,並且在有資料的情況下,能不能直接使用mapping API將欄位的type進行改變?
一般狀況下是不行的~
因為這樣必須要重新index,如果有幾百萬筆資料的話會非常花時間
我們可以使用Reindex API來更改現有index的欄位類型
最基礎的就是如下:
設置好source與destination的index,切記這兩個index都要已經存在
POST /_reindex
{
  "source": {
    "index": "test-1"
  },
  "dest": {
    "index": "test-2"
  }
}
一些進階用法:
POST /_reindex
{
	"source": {
    "index": "test-1"
		"query": {
			"match": {}
		}
  },
  "dest": {
    "index": "test-2"
  }
}
POST /_reindex
{
	"source": {
    "index": "test-1"
		"_source": ["column-1", "column-2"]
  },
  "dest": {
    "index": "test-2"
  }
}
// manual
POST /_reindex
{
  "source": {
    "index": "test-1",
    "slice": {
      "id": 0,
      "max": 2
    }
  },
  "dest": {
    "index": "test-2"
  }
}
// automatic
POST _reindex?slices=5&refresh
{
  "source": {
    "index": "test-1"
  },
  "dest": {
    "index": "test-2"
  }
}
POST /_reindex
{
"source": {
    "remote": {
      "host": "http://otherhost:9200",
      "username": "",
      "password": ""
    },
    "index": ["remote-index-2", "remote-index-2"],
    "_source": ["id", "name"],
    "query": {
      "match_all": {}
    }
}, "dest": {
"index": "local-dest-index",
"routing": "=user"
  },
  "script": {
    "source": """ctx._source.comment = ctx._source-remove("content")""",
    "lang": "painless"
  },
}
Multi-field mappings:
有時候同一個欄位的資料性質,可能需要多種方式去操作,有時候可能要用全文搜索去找,但是有時又想要能使用term-level query
例如車子的型號是:車廠 型號(ex: Honda CR-V)
我就可能需要使用term-level query去把所有Honda CR-V的車子找出來
但是同時我又想要單獨去找CR-V的型號
因此可以使用multi-fields
PUT /multi_field_test
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "desc": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      }
    }
  }
}
以上圖為例:
index template:
之前有提過,ES很常會接收來自filebeat、metricbeat等的資料,或是常要接收一些log值
索引名稱可能如下:
access-log-2023-01
access-log-2023-02
access-log-2023-03
這時後我們就可以使用index template,創建符合特定條件名稱的索引,讓他們的mapping設定一樣的條件
PUT /_template/access-logs
{
  "index_patterns": ["access-logs-*"],
  "settings": {
    "number_of_shards": 1
  },
  "mappings": {
    "properties": {
      "@timestamp": {
        "type": "date"
      },
      "http.response.status_code": {
        "type": "long"
      }
    }
  }
}
此時我們直接創一個索引,並且直接看mapping
PUT /access-logs-2023-09
GET /access-logs-2023-09/_mapping

可以看到因為匹配到我們的模板,mapping直接設定好了
不過有以下幾點要注意:
今天的內容一樣非常非常多
我們大致介紹了mapping的類型
並且也說明了,如果我們建立好mapping跟index,當需求改變時
我們可以透過一些API來幫助我們去新增欄位,或是轉移資料到新索引上
但是在一開始我們可能對於整個專案業務不熟悉的狀況下
我們甚至可能對於我們是不是要再細分處理原有的欄位
或是對於送進索引的row data,要不要再分割成更適合我們需求的欄位也不太清楚
並且可能我們也不想要使用額外的空間去儲存這些暫時性的資料,那應該怎麼做?
明天來介紹Runtime fields,這個在開發初期也算是很好用的功能,並可以解決上面的問題
也介紹在實務上通常會怎麼使用
參考資料
script:
https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting-using.html
reindex API:
https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-reindex.html
index templates:
https://www.elastic.co/guide/en/elasticsearch/reference/current/index-templates.html